package cn.lichenfei.fxui.controls.skin;

import cn.lichenfei.fxui.controls.CFCarousel;
import javafx.animation.*;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.ListChangeListener;
import javafx.geometry.Pos;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Circle;
import javafx.util.Duration;
import org.kordamp.ikonli.antdesignicons.AntDesignIconsOutlined;
import org.kordamp.ikonli.javafx.FontIcon;

import java.util.List;
import java.util.function.Consumer;

public class CFCarouselSkin extends SkinBase<CFCarousel> {

    private StackPane itemContainer = new StackPane();
    private Button leftButton = new Button();
    private Button rightButton = new Button();
    private Indicator indicator = new Indicator();
    private StackPane toolPane = new StackPane(leftButton, rightButton, indicator);
    private StackPane container = new StackPane(itemContainer, toolPane);
    //
    private IntegerProperty indexProperty = new SimpleIntegerProperty(0);
    private List<ImageView> imageViews;
    // 动画相关
    private Duration interval = Duration.millis(3000); // 隔多少时间切换下一个
    private Duration duration = Duration.millis(500); // 动画时间
    private Button TRANSITION_NODE = new Button();
    //
    private PauseTransition PT = new PauseTransition(interval); // 停顿动画
    private TranslateTransition TT = new TranslateTransition(duration, TRANSITION_NODE);
    private SequentialTransition ST = new SequentialTransition(PT); // 顺序动画

    public CFCarouselSkin(CFCarousel control) {
        super(control);
        initLayout();
        initEvent(control);
        getChildren().setAll(container);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void layoutChildren(final double x, final double y,
                                  final double w, final double h) {
        super.layoutChildren(x, y, w, h);
    }

    private void initLayout() {
        container.getStyleClass().add("container");
        toolPane.getStyleClass().add("tool-pane");
        leftButton.setGraphic(FontIcon.of(AntDesignIconsOutlined.LEFT));
        rightButton.setGraphic(FontIcon.of(AntDesignIconsOutlined.RIGHT));
        StackPane.setAlignment(leftButton, Pos.CENTER_LEFT);
        StackPane.setAlignment(rightButton, Pos.CENTER_RIGHT);
        StackPane.setAlignment(indicator, Pos.BOTTOM_CENTER);
        leftButton.getStyleClass().add("left-button");
        rightButton.getStyleClass().add("right-button");
        indicator.getStyleClass().add("indicator");
    }

    private void initEvent(CFCarousel control) {
        // 指示器选中事件
        indicator.selectedChange(index -> {
            if (indexProperty.isNotEqualTo(index).get()) {
                play(imageViews.get(index), index > indexProperty.get());
            }
        });
        // 上一个
        leftButton.setOnMouseClicked(event -> previous());
        // 下一个
        rightButton.setOnMouseClicked(event -> next());
        //监听轮播内容变化
        control.imageViewsProperty().addListener((ListChangeListener<ImageView>) c -> initCarousel(control));
        initCarousel(control);
    }

    /**
     * 初始化轮播图
     */
    private void initCarousel(CFCarousel control) {
        //重新初始化
        indexProperty.set(0);
        this.imageViews = control.getImageViews();
        itemContainer.getChildren().setAll(imageViews.get(indexProperty.get())); // 设置默认展示的节点
        indicator.resetChildren(imageViews.size()); // 初始化指示器
        // 监听当前播放的节点：选中
        indicator.setSelected(indexProperty.get());
        indexProperty.addListener((observable, oldValue, newValue) -> indicator.setSelected(newValue.intValue()));
        // 自动播放
        autoPlay();
        control.hoverProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue) {
                if (!Animation.Status.RUNNING.equals(TT.getStatus())) { // 动画非运行状态，停止动画。
                    ST.stop();
                }
            } else {
                autoPlay();
            }
        });
    }

    private void autoPlay() {
        ST.setCycleCount(-1);
        PT.setOnFinished(event -> next());
        ST.play();
    }

    /**
     * 上一个
     */
    private void previous() {
        int size = imageViews.size();
        if (size <= 1) {
            return;
        }
        int i = indexProperty.get() - 1;
        if (i < 0) {
            i = size - 1;
        }
        play(imageViews.get(i), false);
    }

    /**
     * 下一个
     */
    private void next() {
        int size = imageViews.size();
        if (size <= 1) {
            return;
        }
        int i = indexProperty.get() + 1;
        if (i >= size) {
            i = 0;
        }
        play(imageViews.get(i), true);
    }

    private void play(ImageView imageView, boolean f) {
        if (Animation.Status.RUNNING.equals(TT.getStatus())) { // 动画正在运行，
            return;
        }
        //设置裁剪，绑定裁剪
        CFCarousel skinnable = getSkinnable();
        double width = skinnable.getWidth();
        double height = skinnable.getHeight();
        Circle circle = new Circle();
        circle.setRadius(0);
        circle.setTranslateY(height);
        circle.setTranslateX(f ? 0 : width);
        TRANSITION_NODE.translateXProperty().addListener((observableValue, number, t1) -> circle.setRadius(t1.doubleValue()));
        imageView.setClip(circle);
        // 添加新节点到容器
        itemContainer.getChildren().add(imageView);
        itemContainer.getChildren().get(0).setClip(null); // 取消之前的裁剪
        indexProperty.set(imageViews.indexOf(imageView)); // 设置当前播放的index
        //动画参数
        TT.setFromX(0);
        TT.setToX(Math.sqrt(width * width + height * height));
        TT.play();
        TT.setOnFinished(actionEvent -> {
            // 动画完成删除被隐藏的节点
            itemContainer.getChildren().remove(0);
            if (skinnable.isHover() && ST != null) { // 动画结束并且鼠标在当前容器，停止动画
                ST.stop();
            }
        });
    }

    /**
     * 指示器
     */
    public class Indicator extends HBox {

        private ToggleGroup toggleGroup = new ToggleGroup();

        public Indicator() {
            initLayout();
        }

        public void resetChildren(int number) {
            getChildren().clear();
            for (int i = 0; i < number; i++) {
                getChildren().add(getToggleButton(i));
            }
        }

        /**
         * 指示器选中事件
         *
         * @param consumer
         */
        public void selectedChange(Consumer<Integer> consumer) {
            toggleGroup.selectedToggleProperty().addListener((observableValue, toggle, t1) -> {
                int i = getChildren().indexOf(t1);
                if (i != -1) {
                    consumer.accept(i);
                }
            });
        }

        public void setSelected(int index) {
            ((ToggleButton) getChildren().get(index)).setSelected(true);
        }

        private void initLayout() {
            this.setMaxHeight(Double.NEGATIVE_INFINITY);
            this.setMaxWidth(Double.NEGATIVE_INFINITY);
        }

        // 设置指示器按钮样式
        private ToggleButton getToggleButton(int index) {
            ToggleButton tb = new ToggleButton();
            tb.setToggleGroup(toggleGroup);
            tb.setUserData(index);
            tb.setOnMouseClicked(event -> tb.setSelected(true));
            return tb;
        }
    }
}
